home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / amitcp / kern / subr_prf.c < prev    next >
C/C++ Source or Header  |  1994-02-16  |  18KB  |  697 lines

  1. RCS_ID_C="$Id: subr_prf.c,v 1.33 1994/02/16 06:07:33 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * HISTORY
  8.  * $Log: subr_prf.c,v $
  9.  * Revision 1.33  1994/02/16  06:07:33  jraja
  10.  * Replaced RawDoFmt() calls with vcsprintf(), which now does the formatting
  11.  * itself. Changed stuffchar() to cs_putchar(), added csprintn() to print
  12.  * out numbers.
  13.  * Changed vlog() to return the number of characters written, changed
  14.  * printf() to use vlog() (wheir code was identical).
  15.  *
  16.  * Revision 1.32  1994/01/05  10:27:30  jraja
  17.  * Added IntuitionBase opening and closing to the panic().
  18.  * Note: using a local library base variable might not work in GCC?
  19.  * 
  20.  * Revision 1.31  1993/12/21  22:06:48  jraja
  21.  * Changed implicit structure member (s_sec) to explicit (tv_secs) on timeval.
  22.  *
  23.  * Revision 1.30  1993/11/06  23:51:22  ppessi
  24.  * Added csprintf(), sprintf function using CSource.
  25.  * Added vsprintf() and vcsprintf() as well.
  26.  *
  27.  * Revision 1.29  1993/10/07  22:41:34  ppessi
  28.  * Added time to the log message.
  29.  *
  30.  * Revision 1.28  1993/05/16  00:11:12  jraja
  31.  * Removed redundant volatile keyword.
  32.  *
  33.  * Revision 1.27  93/05/14  15:54:17  15:54:17  ppessi (Pekka Pessi)
  34.  * Minor prototype fixes.
  35.  * 
  36.  * Revision 1.26  93/05/05  16:10:15  16:10:15  puhuri (Markus Peuhkuri)
  37.  * Fixes for final demo.
  38.  * 
  39.  * Revision 1.25  93/05/04  12:40:07  12:40:07  puhuri (Markus Peuhkuri)
  40.  * Fixed PANICBUFFER (SASC didnt like implicit alloca())
  41.  * Now log takes care of keeping level on right range.
  42.  * 
  43.  * Revision 1.24  93/04/29  22:02:44  22:02:44  puhuri (Markus Peuhkuri)
  44.  * fixed variable names to use configuration structure.
  45.  * 
  46.  * Revision 1.23  93/04/28  12:59:05  12:59:05  puhuri (Markus Peuhkuri)
  47.  * Fixed stdargs.h to stdarg.h
  48.  * 
  49.  * Revision 1.22  93/04/27  10:23:19  10:23:19  puhuri (Markus Peuhkuri)
  50.  * Add vlog-function for calling log from API. log() calls now vlog().
  51.  * 
  52.  * Revision 1.21  93/04/26  18:55:08  18:55:08  puhuri (Markus Peuhkuri)
  53.  * Moved contents of closelog to log_deinit() and removed closelog.
  54.  * 
  55.  * Revision 1.20  93/04/26  11:54:46  11:54:46  too (Tomi Ollila)
  56.  * Changed include paths of amiga_api.h, amiga_libcallentry.h and amiga_raf.h
  57.  * from kern to api
  58.  * 
  59.  * Revision 1.19  93/04/23  02:28:38  02:28:38  ppessi (Pekka Pessi)
  60.  * Number and length of logging messages made configureable.
  61.  * 
  62.  * Revision 1.18  93/04/21  19:08:46  19:08:46  puhuri (Markus Peuhkuri)
  63.  * Now checks if process run into panic() was AmiTCP.
  64.  * Now uses new structure to log_msg. (Printing of priority is in
  65.  * NETTRACE)
  66.  * 
  67.  * Revision 1.17  93/04/06  15:15:55  15:15:55  jraja (Jarno Tapio Rajahalme)
  68.  * Changed spl function return value storage to spl_t,
  69.  * changed bcopys and bzeros to aligned and/or const when possible,
  70.  * added inclusion of conf.h to every .c file.
  71.  * 
  72.  * Revision 1.16  93/03/20  07:06:38  07:06:38  ppessi (Pekka Pessi)
  73.  * Fixed memory leak caused by task_remove()
  74.  * 
  75.  * Revision 1.15  93/03/19  14:14:54  14:14:54  too (Tomi Ollila)
  76.  * Code changes at night 17-18 March 1993
  77.  * 
  78.  * Revision 1.14  93/03/15  09:12:42  09:12:42  jraja (Jarno Tapio Rajahalme)
  79.  * Checkin' mods made by ppessi.
  80.  * 
  81.  * Revision 1.13  93/03/13  00:05:31  00:05:31  ppessi (Pekka Pessi)
  82.  * Quick'n'dirty fix for PANICBUFFER; some prototypes fixed. 
  83.  * 
  84.  * Revision 1.12  93/03/10  17:14:12  17:14:12  puhuri (Markus Peuhkuri)
  85.  * Fixed documentation. Now (s)printf returns number of printed chars.
  86.  * 
  87.  * Revision 1.11  93/03/09  13:33:11  13:33:11  puhuri (Markus Peuhkuri)
  88.  * See messages for amiga_log.c/1.10.
  89.  * Now uses new function to get log message.
  90.  * Fixed a bug in closing of log (caused a read from low memory, 0x14)
  91.  * 
  92.  * Revision 1.10  93/03/05  21:11:17  21:11:17  jraja (Jarno Tapio Rajahalme)
  93.  * Fixed includes (again).
  94.  * 
  95.  * Revision 1.9  93/03/05  12:32:33  12:32:33  jraja (Jarno Tapio Rajahalme)
  96.  * Removed #include <kern/amiga_api_protos.h>.
  97.  * 
  98.  * Revision 1.8  93/03/05  03:26:17  03:26:17  ppessi (Pekka Pessi)
  99.  * Compiles with SASC. Initial test version.
  100.  * 
  101.  * Revision 1.7  93/03/02  18:25:12  18:25:12  puhuri (Markus Peuhkuri)
  102.  * Add sprintf() and fixed documentation
  103.  * 
  104.  * Revision 1.6  93/03/02  16:10:35  16:10:35  puhuri (Markus Peuhkuri)
  105.  * Removed amiga.lib functions, fixed memory managment
  106.  * 
  107.  * Revision 1.5  93/02/26  19:44:35  19:44:35  puhuri (Markus Peuhkuri)
  108.  * Modified to use MsgPort as list of free messages,
  109.  * made log() and printf() re-entrant, removed kprintf (replaced w/
  110.  * exec/RawDoFmt()), kernputchar, ksprintn() and logpri.
  111.  * As every BSD/Mach code was removed so was copyright.
  112.  * 
  113.  * Revision 1.4  93/02/25  19:39:25  19:39:25  puhuri (Markus Peuhkuri)
  114.  * Includes fixed, compatible with both GCC and SAS, 
  115.  * function declarations fixed, calls from panic() fixed,
  116.  * checks for various places.
  117.  * 
  118.  * Revision 1.3  93/02/24  17:32:17  17:32:17  puhuri (Markus Peuhkuri)
  119.  * Add printf (for printing to log)
  120.  * 
  121.  * Revision 1.2  93/02/24  17:22:23  17:22:23  puhuri (Markus Peuhkuri)
  122.  * Made program to work much cleanier, still uses Amiga.lib
  123.  * 
  124.  * Revision 1.1  92/12/17  18:19:42  puhuri
  125.  * Initial revision
  126.  *
  127.  */
  128.  
  129. #include <conf.h>
  130.  
  131. #include <sys/param.h>
  132. #include <sys/systm.h>
  133. #include <sys/syslog.h>
  134. #include <sys/time.h>
  135.  
  136. #include <kern/amiga_includes.h>
  137. #include <api/amiga_api.h>
  138. #include <api/amiga_libcallentry.h>
  139. #include <kern/amiga_log.h>
  140. #include <stdarg.h>
  141. #include <intuition/intuition.h>
  142.  
  143. #if __GNUC__
  144. #include <inline/intuition.h>
  145. #elif __SASC
  146. #include <proto/intuition.h>
  147. #endif
  148.  
  149. #include <kern/amiga_main_protos.h>
  150. #include <dos/rdargs.h>        /* CSource */
  151.  
  152. extern void exit(int);
  153.  
  154. void
  155. cs_putchar(unsigned char ch, struct CSource * cs)
  156. {
  157.   if (cs->CS_CurChr < cs->CS_Length 
  158.       && (cs->CS_Buffer[cs->CS_CurChr] = ch))
  159.     cs->CS_CurChr++;
  160. }
  161.  
  162. /****i* bsdsocket.library/panic ******************************************
  163. *
  164. *   NAME    
  165. *    panic -- Inform user from serious failure.
  166. *
  167. *   SYNOPSIS
  168. *    panic(Message, Arguments...)
  169. *
  170. *    void panic( STRPTR, ... )
  171. *
  172. *   FUNCTION
  173. *    Calls api_setfunctions() with no arguments to stop programs using
  174. *    AmiTCP. Writes message to log file. Sets up User Requester to
  175. *    inform user about situation. Avoids self-loops.
  176. *
  177. *
  178. *   INPUTS
  179. *        Messagestring - A pointer to string containing message to show
  180. *        to user and to write to log. It should describe problem so
  181. *        that user can take correcting action if it is failure with
  182. *        his configuration or is able to write bug report if it is
  183. *        a bug withn program.
  184. *
  185. *       Arguments - as in c-library printf()
  186. *
  187. *   RESULT
  188. *        This function does not return.
  189. *
  190. *   EXAMPLE
  191. *        if(Everything==WRONG)
  192. *        panic("Everything is wrong\nGoto sleep");
  193. *
  194. *   NOTES
  195. *        As panic does not return, it should be used only in extreme
  196. *    cases
  197. *
  198. *   BUGS
  199. *
  200. *   SEE ALSO
  201. *    log()
  202. *
  203. ******************************************************************************
  204. *
  205. */
  206.  
  207. #define PANICBUFFERSIZE 512
  208.  
  209. void
  210. panic(const char *fmt,...)
  211. {
  212.   struct EasyStruct panicES = {
  213.     sizeof( struct EasyStruct),
  214.     NULL,
  215.     "AmiTCP PANIC",
  216.     "panic: %s" ,
  217.     "Exit AmiTCP"
  218.   };
  219.   static in_panic = 0;
  220.   struct CSource cs;
  221.   char buffer[PANICBUFFERSIZE];
  222.   va_list ap;
  223.   struct Library *IntuitionBase = NULL; /* local intuitionbase */
  224.   extern struct Task *AmiTCP_Task;
  225.  
  226.   if (!in_panic){
  227.                 /* If we're called previously.. */
  228.     in_panic++;            /* We're in panic now */
  229.     api_setfunctions();        /* Set libraries to return error code */
  230.  
  231.     cs.CS_Buffer = buffer;
  232.     cs.CS_CurChr = 0;
  233.     cs.CS_Length = PANICBUFFERSIZE;
  234.  
  235.     va_start(ap, fmt);
  236.     vcsprintf(&cs, fmt, ap);
  237.     va_end(ap);
  238.     
  239.     log(LOG_EMERG, "panic: %s", buffer); /* Write to log */
  240.   }
  241.   in_panic--;
  242.     
  243.   /*
  244.    * Inform user (if log system has failed...)
  245.    * by opening a requester to the default public screen.
  246.    *
  247.    * Open a local IntuitionBase for the EasyRequestArgs()
  248.    */
  249.   if ((IntuitionBase = OpenLibrary("intuition.library", 37L)) != NULL) {
  250.     EasyRequestArgs(NULL, &panicES, NULL, (char *)&buffer);
  251.     CloseLibrary(IntuitionBase);
  252.     IntuitionBase = NULL;
  253.   }
  254.     
  255.   /*
  256.    * If the caller is not the AmiTCP task, sleep forever. 
  257.    * This should go to API or where ever we came in AmiTCP code
  258.    */
  259.   if (FindTask(NULL) != AmiTCP_Task)
  260.     Wait(0);
  261.  
  262.   Wait(SIGBREAKF_CTRL_F);    /* AmiTCP/IP waits here */
  263.  
  264.   /*
  265.    * Following code is not safe. Probably we should wait infinetely long too...
  266.    */
  267.   deinit_all();            /* This returns !! */
  268.   exit(20);            /* This should be safe... */
  269. }
  270.  
  271. /****i* bsdsockets.library/log ******************************************
  272. *
  273. *   NAME    
  274. *    log -- Write log message to log and/or console.
  275. *
  276. *   SYNOPSIS
  277. *        log(Level, FormatString, arguments...)
  278. *
  279. *    void log( ULONG, STRPTR, ...)
  280. *
  281. *   FUNCTION
  282. *     Writes message given as format string and arguments
  283. *    (printf-style) to both log and console (except if level is
  284. *       LOG_EMERG, LOG_EMERG is generated only by panic and it is
  285. *       written only to the log file as panic() generates an User
  286. *       Requester informing user.
  287. *
  288. *       This function can be called from interrupts.
  289. *
  290. *   INPUTS
  291. *        Level - indicates type of logged message. These levels are
  292. *        defined in sys/syslog.h.
  293. *    FormatString - This is a printf-style format string with some
  294. *        restrictions (notably the floats are not handled).
  295. *    arguments - as in printf() 
  296. *
  297. *   RESULT
  298. *        Returns no value.
  299. *
  300. *   EXAMPLE
  301. *        log(LOG_ERR,
  302. *        "arp: ether address is broadcast for IP address %x!\n",
  303. *            ntohl(isaddr.s_addr));
  304. *    fail=TRUE;
  305. *    break;
  306. *
  307. *   NOTES
  308. *
  309. *   BUGS
  310. *
  311. *   SEE ALSO
  312. *    Your C-compilers printf() documentation.
  313. *
  314. ******************************************************************************
  315. *
  316. */
  317.  
  318. void
  319. log(unsigned long level, const char *fmt, ...)
  320. {
  321.   va_list ap;
  322.  
  323.   va_start(ap, fmt);
  324.   vlog(level, fmt, ap);        /* Call actual function */
  325.   va_end(ap);
  326. }
  327.  
  328. ULONG
  329. vlog(unsigned long level, const char *fmt, va_list ap)
  330. {
  331.   struct log_msg *msg;
  332.   struct timeval now;
  333.   if (msg = (struct log_msg *)GetLogMsg(logReplyPort)) {
  334.     ULONG ret;
  335.     struct CSource cs;
  336.     cs.CS_Buffer = msg->string;
  337.     cs.CS_Length = log_cnf.log_buf_len;
  338.     cs.CS_CurChr = 0;
  339.  
  340.     GetSysTime(&now);
  341.  
  342.     vcsprintf(&cs, fmt, ap);
  343.     msg->level = level & (LOG_FACMASK | LOG_PRIMASK);    /* Level of message */
  344.     ret = msg->chars = cs.CS_CurChr;
  345.     msg->time = now.tv_secs;
  346.     PutMsg(logPort, (struct Message *)msg);
  347.     return ret;
  348.   }
  349.   return 0;
  350. }
  351.  
  352. /****i* bsdsockets.library/printf ******************************************
  353. *
  354. *   NAME    
  355. *    printf -- print to log
  356. *
  357. *   SYNOPSIS
  358. *        printf(FormatString, Arguments...)
  359. *
  360. *    ULONG printf( const char *, ...)
  361. *
  362. *   FUNCTION
  363. *       Prints messages to log
  364. *       As log, also this is callable from interrupts.
  365. *
  366. *       Specially for debugging prints.
  367. *
  368. *   INPUTS
  369. *    FormatString - This is a printf-style format string as for vcsprintf().
  370. *    Arguments - as in C-librarys printf() 
  371. *
  372. *   RESULT
  373. *       Number of characters printed.
  374. *
  375. *   EXAMPLE
  376. *
  377. *        printf("line=%d, val=%x\n", 
  378. *                      __LINE__, very.interesting->value);
  379. *
  380. *   NOTES
  381. *
  382. *   BUGS
  383. *
  384. *   SEE ALSO
  385. *    vcsprintf(), vlog()
  386. *
  387. ******************************************************************************
  388. *
  389. */
  390. ULONG 
  391. printf(const char *fmt, ...)
  392. {
  393. #if 1
  394.   ULONG ret;
  395.   va_list ap;
  396.  
  397.   va_start(ap, fmt);
  398.   ret = vlog(LOG_INFO, fmt, ap);
  399.   va_end(ap);
  400.   
  401.   return ret;
  402. #else
  403.   va_list ap;
  404.   struct log_msg *msg;
  405.   struct timeval now;
  406.  
  407.   if (msg = GetLogMsg(logReplyPort)) {    /* Get next free message */
  408.     struct CSource cs;
  409.  
  410.     GetSysTime(&now);
  411.  
  412.     cs.CS_Buffer = msg->string;
  413.     cs.CS_Length = log_cnf.log_buf_len;
  414.     cs.CS_CurChr = 0;
  415.  
  416.     va_start(ap, fmt);
  417.     vcsprintf(&cs, fmt, ap);
  418.     va_end(ap);
  419.  
  420.     msg->level = LOG_INFO;
  421.     msg->chars = cs.CS_CurChr;
  422.     msg->time = now.tv_secs;
  423.     PutMsg(logPort,(struct Message *)msg);
  424.  
  425.     return (ULONG)cs.CS_CurChr;
  426.   } else
  427.     return 0;
  428. #endif
  429. }
  430.  
  431. /****i* bsdsockets.library/sprintf ******************************************
  432. *
  433. *   NAME    
  434. *    sprintf -- print to buffer
  435. *
  436. *   SYNOPSIS
  437. *        len = sprintf(Buffer, FormatString, Arguments...)
  438. *       len = csprintf(cs, FormatString, Arguments...)
  439. *
  440. *    ULONG sprintf(STRPTR, const char*, ...)
  441. *       ULONG csprintf(struct CSource *, const char*, ...)
  442. *
  443. *   FUNCTION
  444. *     Prints to a simple buffer or to a CSource buffer. These functions
  445. *       are similar to C-library sprintf() with restricted formatting.
  446. *
  447. *   INPUTS
  448. *       Buffer       - Pointer to buffer.
  449. *    FormatString - This is a printf()-style format string with some
  450. *                      restrictions. Numbers are being taken as 'long' by
  451. *                      default, however.
  452. *    Arguments    - as in printf() .
  453. *       cs           - Pointer to CSource structure.
  454. *
  455. *   RESULT
  456. *       Number of characters printed.
  457. *
  458. *   EXAMPLE
  459. *    sprintf(mybuf, "line=%d, val=%x\n", 
  460. *               __LINE__, very.interesting->value);
  461. *
  462. *   BUGS
  463. *       Function sprintf() assumes that no print is longer than 1024 chars.
  464. *       It does not check for buffer owerflow (there no way to check, the
  465. *       definition of sprintf misses it).
  466. *
  467. *       sprintf strings are truncated to maximum of 1024 chars (including
  468. *       final NUL)
  469. *
  470. *   SEE ALSO
  471. *    vcsprintf()
  472. *
  473. ******************************************************************************
  474. *
  475. */
  476.  
  477. ULONG 
  478. vcsprintf(struct CSource *cs, const char *fmt, va_list ap)
  479. {
  480.   ULONG start = cs->CS_CurChr;
  481.   char *p, ch, padc;
  482.   u_long ul;
  483.   int n, base, lflag, tmp, width, precision, leftjustify;
  484.   char buf[sizeof(long) * NBBY / 3 + 2]; /* A long in base 8, plus '\0'. */
  485.  
  486.   if (cs->CS_Length && cs->CS_CurChr < cs->CS_Length) {
  487.  
  488.     for (;;) {
  489.       padc = ' ';
  490.       width = 0; 
  491.       precision = -1;
  492.       leftjustify = FALSE;
  493.       while ((ch = *fmt++) != '%') {
  494.     if (ch == '\0') {
  495.       goto end;
  496.     }
  497.     cs_putchar(ch, cs);
  498.       }
  499.       lflag = 0;
  500. reswitch:    
  501.       switch (ch = *fmt++) {
  502.       case '-':
  503.     leftjustify = TRUE;
  504.     goto reswitch;
  505.       case '0':
  506.     padc = '0';
  507.     goto reswitch;
  508.       case '1': case '2': case '3': case '4':
  509.       case '5': case '6': case '7': case '8': case '9':
  510.     for (width = 0;; ++fmt) {
  511.       width = width * 10 + ch - '0';
  512.       ch = *fmt;
  513.       if (ch < '0' || ch > '9')
  514.         break;
  515.     }
  516.     goto reswitch;
  517.       case '.': /* precision */
  518.     for (precision = 0; (ch = *fmt) >= '0' && ch <= '9'; ++fmt) {
  519.       precision = precision * 10 + ch - '0';
  520.     }
  521.     goto reswitch;
  522.       case 'l':
  523.     lflag = 1;
  524.     goto reswitch;
  525.       case 'b':
  526.     {
  527.       char *tp;
  528.  
  529.       ul = va_arg(ap, int);
  530.       p = va_arg(ap, char *);
  531.       for (tp = csprintn(ul, *p++, buf, sizeof(buf)); ch = *tp++;)
  532.         cs_putchar(ch, cs);
  533.     
  534.       if (!ul)
  535.         break;
  536.  
  537.       for (tmp = 0; n = *p++;) {
  538.         if (ul & (1 << (n - 1))) {
  539.           cs_putchar(tmp ? ',' : '<', cs);
  540.           for (; (n = *p) > ' '; ++p)
  541.         cs_putchar(n, cs);
  542.           tmp = 1;
  543.         } else
  544.           for (; *p > ' '; ++p)
  545.         ;
  546.       }
  547.       if (tmp)
  548.         cs_putchar('>', cs);
  549.     }
  550.     break;
  551.       case 'r':
  552.     p = va_arg(ap, char *);
  553.     vcsprintf(cs, p, va_arg(ap, va_list));
  554.     break;
  555.       case 'c':
  556.     *buf = va_arg(ap, int);
  557.     buf[1] = '\0';
  558.     p = buf;
  559.     goto textout;
  560.       case 's':
  561.     p = va_arg(ap, char *);
  562. textout:
  563.     /*
  564.      * Set width to the maximum width, if maximum width is set, and
  565.      * width exceeds it.
  566.      */
  567.     if (precision > 0 && width > precision)
  568.       width = precision;
  569.     /*
  570.      * spit out necessary pad characters to fill on left, if necessary
  571.      */
  572.     if (width > 0 && !leftjustify && (width -= strlen(p)) > 0)
  573.       while (width--)
  574.         cs_putchar(padc, cs);
  575.     /* take a copy of the original pointer */
  576.     ul = (u_long)p;
  577.     /*
  578.      * Copy the characters, pay attention to the fact that precision
  579.          * may not be exceeded.
  580.      */
  581.     while ((ch = *p++) && precision-- != 0)
  582.       cs_putchar(ch, cs);
  583.     /*
  584.      * spit out necessary pad characters to fill on right, if necessary
  585.      */
  586.     if (width > 0 && leftjustify && (width -= ((u_long)p - ul - 1)) > 0)
  587.       while (width--)
  588.         cs_putchar(' ', cs);
  589.     break;
  590.       case 'd':
  591.       case 'i':
  592.         ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
  593.         if ((long)ul < 0) {
  594.       cs_putchar('-', cs);
  595.       ul = -(long)ul;
  596.     }
  597.     base = 10;
  598.     goto number;
  599.       case 'o':
  600.     ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  601.     base = 8;
  602.     goto number;
  603.       case 'u':
  604.     ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  605.     base = 10;
  606.     goto number;
  607.       case 'p': /* pointers */
  608.       case 'P':
  609.     width = 8;
  610.     padc = '0';
  611.     /* FALLTHROUGH */
  612.       case 'x':
  613.       case 'X':
  614.     ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
  615.     base = 16;
  616. number:
  617.     p = csprintn(ul, base, buf, sizeof(buf));
  618.     tmp = (buf + sizeof(buf) - 1) - p; /* length */
  619.     if (width > 0 && !leftjustify && (width -= tmp) > 0)
  620.       while (width--)
  621.         cs_putchar(padc, cs);
  622.     while (ch = *p++)
  623.       cs_putchar(ch, cs);
  624.     if (width > 0 && leftjustify && (width -= tmp) > 0)
  625.       while (width--)
  626.         cs_putchar(' ', cs);
  627.     break;
  628.       default:
  629.     cs_putchar('%', cs);
  630.     if (lflag)
  631.       cs_putchar('l', cs);
  632.     /* FALLTHROUGH */
  633.       case '%':
  634.     cs_putchar(ch, cs);
  635.       }
  636.     }
  637.  
  638. end:
  639.  
  640.     if (cs->CS_CurChr == cs->CS_Length) {
  641.       cs->CS_CurChr--;            /* must NUL terminate */
  642.     }      
  643.     cs->CS_Buffer[cs->CS_CurChr] = '\0';
  644.     
  645.     return cs->CS_CurChr - start;
  646.   } else {
  647.     /* A pathological case */
  648.     return 0;
  649.   }
  650. }
  651.  
  652. ULONG csprintf(struct CSource *cs, const char *fmt, ...)
  653. {
  654.   va_list ap;
  655.   ULONG len;
  656.  
  657.   va_start(ap, fmt);
  658.   len = vcsprintf(cs, fmt, ap);
  659.   va_end(ap);
  660.   return len;
  661. }
  662.  
  663. ULONG vsprintf(char *buf, const char *fmt, va_list ap)
  664. {
  665.   struct CSource cs;
  666.  
  667.   cs.CS_Buffer = buf;
  668.   cs.CS_CurChr = 0;
  669.   cs.CS_Length = 1024;      /* This is not probably the cleanest way :-) */
  670.  
  671.   return vcsprintf(&cs, fmt, ap);
  672. }
  673.  
  674. ULONG sprintf(char *buf, const char *fmt, ...)
  675. {
  676.   va_list ap;
  677.   ULONG len;
  678.  
  679.   va_start(ap, fmt);
  680.   len = vsprintf(buf, fmt, ap);
  681.   va_end(ap);
  682.   return len;
  683. }
  684.  
  685. char *
  686. csprintn(u_long n, int base, char *buf, int buflen)
  687. {
  688.   register char *cp = buf + buflen - 1;
  689.  
  690.   *cp = 0;
  691.   do {
  692.     cp--;
  693.     *cp = "0123456789abcdef"[n % base];
  694.   } while (n /= base);
  695.   return (cp);
  696. }
  697.